﻿using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Threading;

namespace Reticle
{
    public class Profile
    {
        public void CreateProfile()
        {
            int tabCount = 0;
            WebBrowser browser = new WebBrowser();
            browser.Navigating += new WebBrowserNavigatingEventHandler(browser_Navigating);
            browser.Dock = DockStyle.Fill;
            browser.ScrollBarsEnabled = false;

            browser.Navigate(Application.StartupPath + @"\files\lib\html\template.html");
            while (browser.ReadyState != WebBrowserReadyState.Complete)
            {
                Application.DoEvents();
            }

            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");
            XDocument newDoc = new XDocument(new XElement("Config",
                from p in doc.Element("Config").Elements("Profile")
                orderby int.Parse(p.Element("order").Value)
                select p));

            foreach (XElement xe in newDoc.Descendants("Profile"))
            {
                string id = xe.Element("id").Value;
                string load = xe.Element("load").Value;
                string homechannel = xe.Element("homechannel").Value;

                if (load == "1")
                {
                    Settings settings = new Settings();
                    settings.CdKey1 = xe.Element("cdkey").Value;

                    if (xe.Element("expansion").Value != "null" || xe.Element("expansion").Value != "")
                    {
                        settings.CdKey2 = xe.Element("expansion").Value;
                    }

                    settings.CdKeyOwner = xe.Element("username").Value;
                    settings.Client = xe.Element("product").Value;
                    settings.HomeChannel = xe.Element("homechannel").Value;
                    settings.Password = xe.Element("password").Value;
                    settings.Server = xe.Element("server").Value;
                    settings.Username = xe.Element("username").Value;
                    Manager.CreateBot(settings, id, homechannel);

                    // load specific profile settings
                    Manager.LoadProfileSettings(id);

                    TabPage tabPage = new TabPage(id);
                    if (tabCount <= 0)
                    {
                        tabPage.Controls.Add(browser);
                        tabCount++;
                    }
                    tabPage.Name = id;
                    tabPage.ImageIndex = 1;
                    Program.Window.AddTab(tabPage);
                }
            }
        }

        public static void CreateSingleProfile(string profile)
        {
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");
            XDocument newDoc = new XDocument(new XElement("Config",
                from p in doc.Element("Config").Elements("Profile")
                where p.Element("id").Value == profile
                select p));


            foreach (XElement xe in newDoc.Descendants("Profile"))
            {
                string id = xe.Element("id").Value;
                string load = xe.Element("load").Value;
                string homechannel = xe.Element("homechannel").Value;

                Settings settings = new Settings();
                settings.CdKey1 = xe.Element("cdkey").Value;

                if (xe.Element("expansion").Value != "null" || xe.Element("expansion").Value != "")
                {
                    settings.CdKey2 = xe.Element("expansion").Value;
                }

                settings.CdKeyOwner = xe.Element("username").Value;
                settings.Client = xe.Element("product").Value;
                settings.HomeChannel = xe.Element("homechannel").Value;
                settings.Password = xe.Element("password").Value;
                settings.Server = xe.Element("server").Value;
                settings.Username = xe.Element("username").Value;
                Manager.CreateBot(settings, id, homechannel);

                // load specific profile settings
                Manager.LoadProfileSettings(id);

                TabPage tabPage = new TabPage(id);
                tabPage.Name = id;
                tabPage.ImageIndex = 1;
                Program.Window.AddTab(tabPage);
            }
        }

        // make re-written hyperlinks open with the default browser :)
        private void browser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            bool hashes = false;
            // catch hash download link (implement after bot tells hashes are missing)
            if (e.Url.ToString().Contains("reticle-dl-hashes"))
            {
                foreach (Bot bot in Manager.Bots)
                {
                    if (bot.BotKey == Program.Window.CurrentTabKey())
                    {
                        Thread thread = new Thread(new ParameterizedThreadStart(Manager.DownloadHashes));
                        thread.Start(bot.client.Settings.Client);
                    }
                }
                hashes = true;
                e.Cancel = true;
                
            }

            // don't load hash download links, or the bots template html
            if (!e.Url.ToString().Contains("template.html") && !hashes)
            {
                if (e.Url.ToString().Contains("youtube.com/embed"))
                {
                    // we want to embed this so don't open with default browser
                }
                else
                {
                    System.Diagnostics.Process.Start(e.Url.ToString());
                    e.Cancel = true;
                }
            }
        }

        // get profiles from file
        public static Dictionary<string, string> GetProfiles(string type)
        {
            Dictionary<string, string> d = new Dictionary<string, string>();
            string value = "";
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");
            /*XDocument newDoc = new XDocument(new XElement("Config",
                from p in doc.Element("Config").Elements("Profile")
                orderby int.Parse(p.Element("order").Value)
                select p));*/

            foreach (XElement xe in doc.Descendants("Profile"))
            {
                // get currently loaded profiles (currently)
                if (type == "bot")
                {
                    if (Program.Window.CheckTab(xe.Element("id").Value))
                    {
                        value = "1";
                    }
                    else
                    {
                        value = "0";
                    }
                }
                // get currently loaded profiles from the bots config file
                else if (type == "file")
                {
                    value = xe.Element("load").Value;
                }

                d.Add(xe.Element("id").Value, value);
            }

            return d;
        }

        public static Dictionary<string, string> GetSingleProfile(string id)
        {
            Dictionary<string, string> profile = new Dictionary<string, string>();

            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");
            XDocument newDoc = new XDocument(new XElement("Config",
                from p in doc.Element("Config").Elements("Profile")
                where p.Element("id").Value == id
                orderby int.Parse(p.Element("order").Value)
                select p));

            foreach (XElement xe in newDoc.Descendants("Profile"))
            {
                profile.Add("id", xe.Element("id").Value);
                profile.Add("username", xe.Element("username").Value);
                profile.Add("password", xe.Element("password").Value);
                profile.Add("cdkey", xe.Element("cdkey").Value);

                if (xe.Element("expansion").Value == "null")
                {
                    profile.Add("expansion", "");
                }
                else
                {
                    profile.Add("expansion", xe.Element("expansion").Value);
                }

                profile.Add("product", xe.Element("product").Value);
                profile.Add("server", xe.Element("server").Value);
                profile.Add("homechannel", xe.Element("homechannel").Value);
                profile.Add("load", xe.Element("load").Value);
                profile.Add("order", xe.Element("order").Value);
            }

            return profile;
        }

        public static List<string> GetPlugins(string profile)
        {
            List<string> plugins = new List<string>();
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");

            foreach (XElement xe in doc.Descendants("Profile"))
            {
                if (xe.Element("id").Value == profile)
                {
                    foreach (XElement xe2 in xe.Descendants("plugin"))
                    {
                        // get currently loaded profiles (currently)
                        if (Program.Window.CheckTab(profile))
                        {
                            plugins.Add(xe2.Value);
                        }
                    }
                }
            }

            return plugins;
        }

        public static void SaveProfile(string id, Dictionary<string, string> d, Dictionary<string, bool> plugins)
        {
            Settings settings = new Settings();
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");

            foreach (XElement xe in doc.Descendants("Profile"))
            {
                if (xe.Element("id").Value == id)
                {
                    xe.Element("id").Value = d["id"];
                    xe.Element("username").Value = d["username"];
                    xe.Element("password").Value = d["password"];
                    xe.Element("cdkey").Value = d["cdkey"];

                    if (d["expansion"] == "")
                    {
                        xe.Element("expansion").Value = "null";
                    }
                    else
                    {
                        xe.Element("expansion").Value = d["expansion"];
                    }

                    xe.Element("product").Value = d["product"];
                    xe.Element("server").Value = d["server"];
                    xe.Element("homechannel").Value = d["homechannel"];
                    xe.Element("load").Value = d["load"];
                    xe.Element("order").Value = d["order"];

                    // save plugins
                    // add existing plugins to a list (to avoid duplicates)
                    List<string> existingPlugins = new List<string>();
                    List<XElement> removePlugins = new List<XElement>();
                    foreach (XElement xe2 in xe.Descendants())
                    {
                        if (xe2.Name == "plugin")
                        {
                            foreach (KeyValuePair<string, bool> pair in plugins)
                            {
                                // if user wants to remove this plugin from auto-starting
                                if (xe2.Value == pair.Key && pair.Value == false)
                                {
                                    removePlugins.Add(xe2);
                                }
                            }

                            existingPlugins.Add(xe2.Value);
                        }
                    }

                    // remove plugins that have been set to remove (simple, eh?)
                    foreach (XElement remove in removePlugins)
                    {
                        remove.Remove();
                    }

                    // loop through the plugins from the checked list box list
                    foreach (KeyValuePair<string, bool> pair in plugins)
                    {
                        bool exists = false;

                        // if plugin already exists in this profile config, ignore it
                        if (existingPlugins.Contains(pair.Key))
                        {
                            exists = true;
                        }

                        // if it doesn't already exist and user has checked it, add it
                        if (!exists && pair.Value == true)
                        {
                            XElement newplugin = new XElement("plugin", pair.Key);
                            xe.Add(newplugin);
                        }
                    }

                    // save the file (in case new plugins need to be loaded, we are still saving at the end)
                    doc.Save(Application.StartupPath + @"\files\config.xml");

                    foreach (Bot bot in Manager.Bots)
                    {
                        if (id == bot.BotKey)
                        {
                            settings.Username = d["username"];
                            settings.Password = d["password"];
                            settings.CdKey1 = d["cdkey"];

                            if (d["expansion"] != "")
                            {
                                settings.CdKey2 = d["expansion"];
                            }

                            settings.Client = d["product"];
                            settings.HomeChannel = d["homechannel"];
                            settings.Server = d["server"];

                            bot.ReloadSettings(settings);

                            // check for hashes (no longer needed we check on connect.
                            //bot.checkHashesBot(d["product"]);

                            // re-create the menu for new plugins (on the currently selected tab of course)
                            if (bot.BotKey == Program.Window.CurrentTabKey())
                            {
                                bot.CreateMenu();
                            }

                            // reload the bots plugins (i.e load newly added plugins, as already loaded plugins won't load twice)
                            bot.LoadPlugins();
                        }
                    }
                }
            }

            foreach (XElement xe in doc.Descendants("Verbytes"))
            {
                switch (d["product"])
                {
                    case "STAR":
                    case "SEXP":
                        xe.Element("star").Value = d["verbyte"];
                        break;
                    case "W2BN":
                        xe.Element("w2bn").Value = d["verbyte"];
                        break;
                    case "D2DV":
                    case "D2XP":
                        xe.Element("d2dv").Value = d["verbyte"];
                        break;
                    case "WAR3":
                    case "W3XP":
                        xe.Element("war3").Value = d["verbyte"];
                        break;
                }
            }

            doc.Save(Application.StartupPath + @"\files\config.xml");
            Program.Window.populateMenuProfiles("file");

        }

        public static bool AddProfile(string name)
        {
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");

            // don't allow empty profile name
            if (name == "")
            {
                MessageBox.Show("Profile name cannot be blank.");
                return false;
            }

            bool alreadyExists = false;
            foreach (XElement xe in doc.Descendants("Profile"))
            {
                if (xe.Element("id").Value == name)
                {
                    alreadyExists = true;
                }
            }

            if (!alreadyExists)
            {
                XElement elem = new XElement("Profile",
                    new XElement("id", name),
                    new XElement("username", ""),
                    new XElement("password", ""),
                    new XElement("cdkey", ""),
                    new XElement("expansion", ""),
                    new XElement("product", "STAR"),
                    new XElement("server", ""),
                    new XElement("homechannel", ""),
                    new XElement("showjoinleave", "1"),
                    new XElement("disablequeue", "0"),
                    new XElement("load", ""),
                    new XElement("order", "99")
                );

                doc.Element("Config").Add(elem);

                doc.Save(Application.StartupPath + @"\files\config.xml");

                return true;
            }
            else
            {
                MessageBox.Show("Cannot have the same name for 2 profiles.");
                return false;
            }
        }

        public static void RemoveProfile(string id)
        {
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");
            int count = 0;
            bool remove = true;
            
            // find out if there is only 1 profile left
            foreach (XElement xe in doc.Descendants("Profile"))
            {
                count++;
            }

            if (count <= 1)
            {
                remove = false;
            }

            foreach (XElement xe in doc.Descendants("Profile"))
            {
                if (xe.Element("id").Value == id)
                {
                    if (remove)
                    {
                        xe.RemoveAll();
                    }
                    else
                    {
                        MessageBox.Show("Cannot remove the only remaining profile", "Durp");
                    }
                }
            }

            doc.Descendants().Where(d => !d.DescendantNodes().OfType<XText>().Any(t => t.Value != "")).Remove();

            doc.Save(Application.StartupPath + @"\files\config.xml");
        }

        public static void UnloadProfile(string botKey)
        {
            //Manager.Bots[id].Disconnect();
            Bot botToRemove = null;
            bool removeBot = false;
            foreach (Bot bot in Manager.Bots)
            {
                if (bot.BotKey == botKey)
                {
                    botToRemove = bot;
                    removeBot = true;
                    break;
                }
            }

            if (removeBot)
            {
                Manager.Bots.Remove(botToRemove);
            }
            
            Program.Window.RemoveTab(botKey);
        }
    }
}
